package com.manage.common.core.exception;

import com.manage.common.core.constants.Constant;
import com.manage.common.core.result.JsonResult;
import com.manage.common.core.enums.CommonEnum;
import com.manage.common.core.utils.DefaultProfileUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zhangqing
 * @version V1.0
 * @description 全局异常处理器(只拦截除网关外所有异常)
 * @date 8/12/2020 2:03 PM
 */
@Slf4j
@RestControllerAdvice
@AllArgsConstructor
public class GlobalExceptionHandler {

    private final Environment env;

    /**
     * 请求方式不支持
     */
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    @ResponseStatus(code = HttpStatus.METHOD_NOT_ALLOWED)
    public JsonResult handleException(HttpRequestMethodNotSupportedException e) {
        String errorMessage = String.format("请求方式错误: [%s]", "不支持'" + e.getMethod() + "'请求");
        log.error(e.getMessage(), e);
        return JsonResult.failure(HttpStatus.METHOD_NOT_ALLOWED.value(), errorMessage);
    }

    /**
     * 业务异常
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
    public JsonResult businessException(BusinessException e) {
        String errorMessage = String.format("业务异常: [%s]", e.getMessage());
        log.error(e.getMessage(), e);
        return JsonResult.failure(e.getStatus(), errorMessage);
    }

    /**
     * 权限异常
     */
    @ExceptionHandler(PermissionException.class)
    @ResponseStatus(code = HttpStatus.FORBIDDEN)
    public JsonResult permissionException(PermissionException e) {
        String errorMessage = String.format("权限异常: [%s]", e.getMessage());
        log.error(e.getMessage(), e);
        return JsonResult.failure(e.getStatus(), errorMessage);
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
    public JsonResult notFount(RuntimeException e) {
//        String[] activeProfiles = DefaultProfileUtil.getActiveProfiles(env);
        String errorMessage;
        if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {
            throw e;
        }
        if (e.getCause() instanceof BusinessException) {
            errorMessage = String.format("业务异常: [%s]", e.getMessage());
            return JsonResult.failure(((BusinessException) e.getCause()).getStatus(), errorMessage);
        }
//        if(activeProfiles[0].equals(Constant.PRO)){
//            errorMessage = String.format("系统异常: [%s]", CommonEnum.SERVER_ERROR.getMessage());
//            return JsonResult.failure(HttpStatus.INTERNAL_SERVER_ERROR.value(),errorMessage);
//        }
        log.error("运行时异常:", e);
        errorMessage = String.format("异常: [%s]", e.getMessage());
        return JsonResult.failure(HttpStatus.INTERNAL_SERVER_ERROR.value(), errorMessage);
    }

    /**
     * 拦截sql异常
     */
    @ExceptionHandler(BadSqlGrammarException.class)
    @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
    public JsonResult sqlException(BadSqlGrammarException e) {
//        String[] activeProfiles = DefaultProfileUtil.getActiveProfiles(env);
        String errorMessage;
//        if(activeProfiles[0].equals(Constant.PRO)){
//            errorMessage = String.format("系统异常: [%s]", CommonEnum.SERVER_ERROR.getMessage());
//            return JsonResult.failure(HttpStatus.INTERNAL_SERVER_ERROR.value(),errorMessage);
//        }
        errorMessage = String.format("数据库错误: [%s]", e.getSQLException().getMessage());
        log.error("sql异常:", e);
        return JsonResult.failure(e.getSQLException().getErrorCode(), errorMessage);
    }

    /**
     * 用户账户异常
     */
    @ExceptionHandler(UserAcctException.class)
    @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
    public JsonResult userAcctInvalid(UserAcctException e) {
        String errorMessage = String.format("用户账户异常: [%s]", e.getMessage());
        log.error(e.getMessage(), e);
        return JsonResult.failure(e.getStatus(), errorMessage);
    }

    /**
     * 工具包异常
     */
    @ExceptionHandler(CommonException.class)
    @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
    public JsonResult commonException(CommonException e) {
        String errorMessage = String.format("工具包异常: [%s]", e.getMessage());
        log.error(e.getMessage(), e);
        return JsonResult.failure(e.getStatus(), errorMessage);
    }

    /**
     * 工具包异常
     */
    @ExceptionHandler(Error.class)
    @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
    public JsonResult errorException(Error e) {
        String errorMessage = String.format("系统内部错误: [%s]", e.getMessage());
        log.error(e.getMessage(), e);
        return JsonResult.failure(HttpStatus.INTERNAL_SERVER_ERROR.value(), errorMessage);
    }

    /**
     * 参数校验不通过
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(code = HttpStatus.BAD_REQUEST)
    public JsonResult handleException(MethodArgumentNotValidException e) {
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        String message = allErrors.stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(";"));
        String errorMessage = String.format("参数错误: [%s]", message);
        log.error(e.getMessage(), e);
        return JsonResult.failure(HttpStatus.BAD_REQUEST.value(), errorMessage);
    }

}
